package pro.uccs.service;

import com.alibaba.fastjson.JSON;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.state.DefaultStateKeyGenerator;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import pro.uccs.constant.ISVErrorOauthCode;
import pro.uccs.constant.OpenPlatformConstant;

import java.util.Map;

/**********************************************************
 * Copyright © 2017,北京世纪奥通科技有限公司
 * All Rights Reserved.
 *
 * 文件名称： ${file_name}
 * 摘    要： [简要描述本文件的内容]
 *
 * 初始版本：1.0.0
 * 原 作 者：huangjing
 * 完成日期： 2018/7/6 0006

 * 当前版本： 1.0.0
 * 作    者： huangjing
 * 完成日期： 2018/7/6 0006
 *
 *****************************************************************/
public class DemoService {
    /**
     * 授权请求服务
     */
    private OAuth2RestTemplate oAuth2RestTemplate;
    /**
     * 授权码请求资源
     */
    private AuthorizationCodeResourceDetails resource;


    /**
     * 通用授权获取开放平台资源
     *
     * @param sign      参数签名
     * @param method    资源方法
     * @param clientId  应用链接id
     * @param session   是否需要授权会话
     * @param timestamp 时间戳
     * @return
     */
    public String getResourceByAuthorization(String sign, String method, String clientId, String session, String timestamp,String param_json) {

        /**
         * 请求参数封装
         */
        //请求资源服务器地址
        String url = OpenPlatformConstant.RESOURCE_SERVER_URI ;
        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        postParameters.add("method", method);
        postParameters.add("client_id",clientId);
        postParameters.add("session",session);
        postParameters.add("timestamp",timestamp);
        postParameters.add("sign",sign);
        postParameters.add("param_json",param_json);
        HttpEntity<MultiValueMap<String, String>> requestEntity  = new HttpEntity<MultiValueMap<String, String>>(postParameters, null);
        ResponseEntity result = null;
        /**
         * 访问当前的资源
         * 第一次访问会自动获取授权码并且交换回访问资源令牌
         * 后续访问将使用本地缓存不再更新令牌
         */
        try {
            result =  oAuth2RestTemplate.postForEntity(url, requestEntity, String.class);
        }catch (Exception ex){
            Throwable throwable = ex.getCause();
            if(throwable!=null && throwable.getMessage()!=null){
                if(throwable.getMessage().equals(ISVErrorOauthCode.POSTACCESS_TOKEN_SERVER_ERROR.code())){
                    System.out.println("授权服务器内部服务异常，请联系管理员");
                }
            }
            //授权业务异常，需往外抛
            if(ex instanceof UserRedirectRequiredException){
                throw ex;
            }
        }

        /**
         * 访问成功后可以获取当前资源令牌
         */
        OAuth2AccessToken oAuth2AccessToken = oAuth2RestTemplate.getOAuth2ClientContext().getAccessToken();

        /**
         * 如果是分布式系统，需要共享一个请求令牌 可以将此令牌进行保存
         * 下次使用该令牌进行访问，请求将不会重新申请令牌
         */
        String tokenValue = oAuth2AccessToken.getValue();

        String resultStr = JSON.toJSONString(result.getBody());

        return resultStr;
    }

    public String getUrl() {

        //签名
        String sign = "88d98e1699c84958";
        //资源方法名称
        String method = "simba.user.info";
        //应用id
        String client_id = OpenPlatformConstant.CLIENT_ID;
        String paramsStr = "method=" + method + "&client_id=" + client_id + "&SESSION=123456&timestamp=123456&sign=" + sign;
        String url = OpenPlatformConstant.RESOURCE_SERVER_URI + "?" + paramsStr;
        return url;
    }

    /**
     * 通过本地令牌访问资源
     *
     * @param accessToken 资源请求成功后，本地保存令牌，绑定本地用户
     * @return
     */
    public String getResourceByAccessToken(String accessToken, String sign, String method, String clientId, String session, String timestamp) {
        /**
         * 请求参数封装
         */
        String paramsStr = "method=" + method + "&client_id=" + clientId + "&session=" + session + "&timestamp=" + timestamp + "&sign=" + sign ;
        //请求资源服务器地址
        String url = OpenPlatformConstant.RESOURCE_SERVER_URI + "?" + paramsStr;
        /**
         * 设置令牌
         */
        OAuth2ClientContext oAuth2ClientContext = oAuth2RestTemplate.getOAuth2ClientContext();

        OAuth2AccessToken oAuth2AccessToken = new DefaultOAuth2AccessToken(accessToken);
        oAuth2ClientContext.setAccessToken(oAuth2AccessToken);
        ResponseEntity result = null;
        try {
            result = oAuth2RestTemplate.postForEntity(url, null, String.class);
        }catch (Exception ex){
            Throwable throwable = ex.getCause();
            if(throwable!=null && throwable.getMessage()!=null){
                if(throwable.getMessage().equals(ISVErrorOauthCode.POSTACCESS_TOKEN_SERVER_ERROR.code())){
                    System.out.println("授权服务器内部服务异常，请联系管理员");
                }
            }
            //授权业务异常，需往外抛
            if(ex instanceof UserRedirectRequiredException){
                throw ex;
            }

        }
        String resultStr = JSON.toJSONString(result.getBody());
        System.out.println(resultStr);
        return resultStr;
    }

    /**
     * 快速授权，通过终端信息获取授权码
     *
     * @param hashKey      终端打开应用临时授权码
     * @param clientId     应用连接id
     * @param token        终端token 用于校验当前用户登陆状态
     * @param enterpriseId 企业id 当前授权的企业id
     * @return
     */
    public String getAuthorizationCodeByQuickAuthorization(String hashKey, String clientId, String token, String enterpriseId) {

        String authorizationUrl = OpenPlatformConstant.OPEN_AUTHORIZE_PERSONAL + "?";

        RestTemplate restTemplate = new RestTemplate();

        String param = "token=" + token + "&hashkey=" + hashKey + "&clientId=" + clientId + "&enterpriseId=" + enterpriseId;

        authorizationUrl += param;

        /**
         * 通过快速授权通过到，获取授权码
         */
        ResponseEntity responseEntity = restTemplate.postForEntity(authorizationUrl, null, Map.class);

        String code = JSON.toJSONString(responseEntity.getBody());

        return code;
    }

    /**
     * 通过授权码 获取资源
     *
     * @param code      授权码
     * @param sign      参数签名
     * @param method    资源方法
     * @param clientId  应用链接id
     * @param session   是否需要授权会话
     * @param timestamp 时间戳
     * @return
     */
    public String getResourceByAuthorizationCode(String code, String sign, String method, String clientId, String session, String timestamp) {

        /**
         * 请求参数封装
         */
        String paramsStr = "method=" + method + "&client_id=" + clientId + "&session=" + session + "&timestamp=" + timestamp + "&sign=" + sign;
        //请求资源服务器地址
        String url = OpenPlatformConstant.RESOURCE_SERVER_URI + "?" + paramsStr;

        /**
         * 设置授权码
         */
        OAuth2ClientContext oAuth2ClientContext = oAuth2RestTemplate.getOAuth2ClientContext();

        AccessTokenRequest accessTokenRequest = oAuth2RestTemplate.getOAuth2ClientContext().getAccessTokenRequest();
        accessTokenRequest.setAuthorizationCode(code);
        accessTokenRequest.setStateKey(new DefaultStateKeyGenerator().generateKey(resource));
        accessTokenRequest.setPreservedState(OpenPlatformConstant.PRESERVED_STATE);
        /**
         * 设置回调地址
         */
        oAuth2ClientContext.setPreservedState(accessTokenRequest.getStateKey(), accessTokenRequest.getPreservedState());

        /**
         * 正式请求资源
         */
        ResponseEntity result = null;
        try {
            result = oAuth2RestTemplate.postForEntity(url, null, String.class);
        }catch (Exception ex){
            Throwable throwable = ex.getCause();
            if(throwable!=null && throwable.getMessage()!=null){
                if(throwable.getMessage().equals(ISVErrorOauthCode.POSTACCESS_TOKEN_SERVER_ERROR.code())){
                    System.out.println("授权服务器内部服务异常，请联系管理员");
                }
                if(throwable.getMessage().equals(ISVErrorOauthCode.POSTACCESS_TOKEN_CODE_ERROR.code())){
                    System.out.println("授权码错误，请重新发起授权流程");
                }
            }
        }
        Map<String,Object> resultMap = JSON.parseObject(JSON.toJSONString(result.getBody()),Map.class);
        if(resultMap.get("msgCode").toString().equals(ISVErrorOauthCode.TOKEN_HAS_EXPIRED.code())){
            oAuth2ClientContext.setAccessToken(null);
        }
        System.out.println(JSON.toJSONString(result.getBody()));
        return JSON.toJSONString(result.getBody());
    }


    public void setOAuth2RestTemplate(OAuth2RestTemplate oAuth2RestTemplate) {
        this.oAuth2RestTemplate = oAuth2RestTemplate;
    }

    public void setAuthorizationCodeResourceDetails(AuthorizationCodeResourceDetails resource) {
        this.resource = resource;
    }

}
